<!DOCTYPE html>
<html>
    <head>
        <title>Subscribing should provide a P-256 ECDH public key.</title>
        <link rel="manifest" href="resources/push_manifest.json">
        <script src="../resources/testharness.js"></script>
        <script src="../resources/testharnessreport.js"></script>
        <script src="../serviceworker/resources/test-helpers.js"></script>
    </head>
    <body>
        <script>
            // Serializes |buffer| to a base64-encoded string.
            function SerializeArrayBuffer(buffer) {
                return btoa(String.fromCharCode.apply(null, new Uint8Array(buffer)));
            }

            // When running this test manually, grant permission when prompted.
            // This test verifies that push subscriptions get an ECDH P-256 key
            // that can be used on the application server to encrypt payloads.
            async_test(function(test) {
                var workerUrl = 'resources/empty_worker.js';
                var workerScope = 'resources/scope/' + location.pathname;
                var swRegistration, encryptionKey, encryptionAuth;

                // Length of a NIST P-256 point in uncompressed form per SEC1 2.3.3.
                var EXPECTED_KEY_LENGTH = 65;

                // Minimum length of the authentication information, in bytes.
                var MINIMUM_AUTH_LENGTH = 12;

                // The first byte in an uncompressed P-256 point per SEC1 2.3.3.
                var UNCOMPRESSED_POINT_FORM = 0x04;

                service_worker_unregister_and_register(test, workerUrl, workerScope)
                    .then(function(serviceWorkerRegistration) {
                        swRegistration = serviceWorkerRegistration;
                        return wait_for_state(test, swRegistration.installing, 'activated');
                    })
                    .then(function() {
                        if (window.testRunner)
                            testRunner.setPermission('push-messaging', 'granted', location.origin, location.origin);

                        return swRegistration.pushManager.subscribe({ userVisibleOnly: true });
                    })
                    .then(function(pushSubscription) {
                        assert_own_property(PushSubscription.prototype, 'getKey');

                        var key = pushSubscription.getKey('p256dh');

                        assert_not_equals(key, null);
                        assert_equals(key.byteLength, EXPECTED_KEY_LENGTH);

                        // The same ArrayBuffer instance should be returned on multiple calls.
                        assert_equals(key, pushSubscription.getKey('p256dh'));

                        // The first byte of the key should be the uncompressed point form indicator.
                        assert_equals(new Uint8Array(key)[0], UNCOMPRESSED_POINT_FORM);

                        // Verify that authentication information is available in the subscription.
                        var auth = pushSubscription.getKey('auth');

                        assert_not_equals(auth, null);
                        assert_true(auth.byteLength >= MINIMUM_AUTH_LENGTH);

                        // Getting a key with an unsupported algorithm should throw an exception.
                        assert_throws_js(TypeError, () => pushSubscription.getKey('petercurve9001'));

                        encryptionKey = SerializeArrayBuffer(key);
                        encryptionAuth = SerializeArrayBuffer(auth);

                        return swRegistration.pushManager.getSubscription();
                    })
                    .then(function(pushSubscription) {
                        assert_equals(SerializeArrayBuffer(pushSubscription.getKey('p256dh')), encryptionKey);
                        assert_equals(SerializeArrayBuffer(pushSubscription.getKey('auth')), encryptionAuth);

                        return service_worker_unregister_and_done(test, workerScope);
                    })
                    .catch(unreached_rejection(test));

            }, 'Subscribing should provide a P-256 ECDH public key');
        </script>
    </body>
</html>
